﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Word;
using Microsoft.Office.Tools.Word.Extensions;
using biolit_config;
using System.IO;
using System.Windows.Forms;
using OntologyCache;
using System.Diagnostics;
using UCSD_BioLit.Properties;
using Microsoft.Win32;
using Microsoft.Office.Core;

namespace UCSD_BioLit
{
    public partial class ThisAddIn
    {
        public SmartTag m_BioLitTags = null;
        public SmartTag m_UniprotTag = null;
        public SmartTag m_PDBTag = null;
        public SmartTag m_NCBITag = null;
        ApplicationEvents_Handlers appHandlers = new ApplicationEvents_Handlers();
        public static string BIOLIT_NS_URI = "http://biolit.ucsd.edu/biolitschema";
        public static string ONTOLOGY_NS_URI = "http://biolit.ucsd.edu/biolitschema1";
        public static string DB_NS_URI = "http://biolit.ucsd.edu/biolitschema2";
        private List<DocumentWrapper> AllDocs = new List<DocumentWrapper>();

        private Office.CommandBarButton TextMenuControl = null;
        private string TextMenuTag = "515BFD2C922B483f90F20A03171A29FB";
        private string TextMenuID = "C41EB56BFF844f22B10A57E54405E019";

        private Office.CommandBarButton SpellingMenuControl = null;
        private string SpellingMenuTag = "31BC6194C29B48b695A6287B17F348E8";
        private string SpellingMenuID = "4D4FF17DB7C44c339CD07CBEC42C9D43";

        private Office.CommandBarButton GrammarMenuControl = null;
        private string GrammarMenuTag = "32CA70F8522B46ea9E781D090816905E";
        private string GrammarMenuID = "2C97E7E683B84d0488247BB2EB703B3B";

        public SmartTagHandlers m_sth = new SmartTagHandlers();
        public bool IsTermRecognitionOn = false;

        public List<OntologyCache.OntologyInfo> m_Ontologies = new List<OntologyCache.OntologyInfo>();
        public List<OntList> m_SelectedOntologies = new List<OntList>();

        public Word.XMLNamespace schemaRef = null;
        public Word.XMLNamespace ontSchemaRef = null;
        public Word.XMLNamespace dbSchemaRef = null;

        /// <summary>
        /// class name for exception title.
        /// </summary>
        private const string ExceptionTitle = "ThisAddIn.cs";

        /// <summary>
        /// contains the folder location where the application is installed.
        /// </summary>
        private string _assemblyDirectoryName;

        /// <summary>
        /// registry entry for the addin.
        /// </summary>
        private readonly string AddInRegistryKeyPath = @"Software\Microsoft\Office\Word\Addins\UCSD_BioLit";

        /// <summary>
        /// The current word document.
        /// </summary>
        private static Microsoft.Office.Tools.Word.Document wordDoc;

        /// <summary>
        /// app folder path for the custom template.
        /// </summary>
        private readonly string dotxFilePath = @"Biolit_TechPreview_Dec_2009\Ontology.dotx";

        /// <summary>
        /// Manifest key name.
        /// </summary>
        private readonly string AddInManifestKeyName = @"Manifest";

        /// <summary>
        /// custom template name.
        /// </summary>
        private readonly string DotxFileName = @"\Ontology.dotx";

        /// <summary>
        /// This is used to identify addin startup.
        /// </summary>
        private bool IsFirstTime;

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            BootStrap bs = new BootStrap();
            bs.BootStrapSequence();
            Biolit_Settings.LoadSettings();

            // get the application installed folder location.
            _assemblyDirectoryName = GetAssemblyDirectoryName();

            RegisterSchema();

            WireEvents();

            this.ClearOldMenuOptions();

            // mark the addin startup.
            this.IsFirstTime = true;

            // check for missing ontologies. 
            ToParseMissingOntologies();

            this.CustomTaskPanes.Add(new BioLitTaskPane(), Resources.BioLitActionPaneTitle);
        }

        /// <summary>
        /// Clears the Ontology Menu Options created by the older version of our Add-in.
        /// </summary>
        private void ClearOldMenuOptions()
        {
            foreach (string contextMenuName in ContextMenuHelper.OntologyContextMenus)
            {
                try
                {
                    CommandBar contextMenu = Globals.ThisAddIn.Application.CommandBars[contextMenuName.ToString()];

                    if (contextMenu != null)
                    {
                        switch (contextMenu.Name)
                        {
                            case "Text":
                                this.ClearMenuOption(contextMenu, this.TextMenuTag);
                                break;

                            case "Spelling":
                                this.ClearMenuOption(contextMenu, this.SpellingMenuTag);
                                break;

                            case "Grammar (2)":
                                this.ClearMenuOption(contextMenu, this.GrammarMenuTag);
                                break;

                            default:
                                break;
                        }
                    }

                    ((Microsoft.Office.Interop.Word.Template)Globals.ThisAddIn.Application.ActiveDocument.get_AttachedTemplate()).Saved = true;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message, ExceptionTitle);
                }
            }
        }

        /// <summary>
        /// Clears the old Context menu option from the given menu.
        /// </summary>
        /// <param name="contextMenu">The context menu from which the option needs to be removed.</param>
        /// <param name="tagId">TagId of the control to uniquely identify the control.</param>
        private void ClearMenuOption(CommandBar contextMenu, string tagId)
        {
            CommandBarButton popupControl = (CommandBarButton)contextMenu.FindControl(
                            MsoControlType.msoControlButton, Type.Missing, tagId, true, true);

            if (popupControl != null)
            {
                popupControl.Delete(true);
            }
        }

        /// <summary>
        /// Method to find the assembly directory name.
        /// </summary>
        /// <returns>
        /// Returns the install path of the AddIn from the registry.
        /// </returns>
        private string GetAssemblyDirectoryName()
        {
            string addInInstallPath = String.Empty;

            using (RegistryKey addInKey = Registry.CurrentUser.OpenSubKey(AddInRegistryKeyPath, false))
            {
                if (addInKey != null)
                {
                    var registryValue = addInKey.GetValue(AddInManifestKeyName);

                    if (registryValue != null)
                    {
                        var registryPath = registryValue.ToString();

                        // Path might contain "|vstolocal". "|" is an invalid character and needs to be removed.
                        int invalidCharPosition = registryPath.IndexOfAny(Path.GetInvalidPathChars());
                        while (invalidCharPosition > -1)
                        {
                            registryPath = registryPath.Remove(invalidCharPosition, 1);
                            invalidCharPosition = registryPath.IndexOfAny(Path.GetInvalidPathChars());
                        }

                        addInInstallPath = Path.GetDirectoryName(registryPath);
                    }
                }
            }

            return addInInstallPath;
        }

        private void WireEvents()
        {
            Application.DocumentBeforeSave += new Microsoft.Office.Interop.Word.ApplicationEvents4_DocumentBeforeSaveEventHandler(Application_DocumentBeforeSave);
            Application.WindowBeforeDoubleClick += new Microsoft.Office.Interop.Word.ApplicationEvents4_WindowBeforeDoubleClickEventHandler(appHandlers.Application_WindowBeforeDoubleClick);

            Application.DocumentOpen += new Microsoft.Office.Interop.Word.ApplicationEvents4_DocumentOpenEventHandler(appHandlers.Application_DocumentOpen);
            ((Word.ApplicationEvents4_Event)Application).NewDocument += new Microsoft.Office.Interop.Word.ApplicationEvents4_NewDocumentEventHandler(appHandlers.Application_DocumentNew);
            Application.WindowActivate += new Microsoft.Office.Interop.Word.ApplicationEvents4_WindowActivateEventHandler(Application_WindowActivate);

            Application.WindowBeforeRightClick += ContextMenuHelper.Instance().WindowBeforeRightClick;
            Application.DocumentBeforeClose += ContextMenuHelper.Instance().DocumentBeforeClose;
            Application.DocumentBeforeSave += ContextMenuHelper.Instance().DocumentBeforeSave;
        }

        /// <summary>
        /// This event is handled since for a saved document when double clicked we get the active document object in this event during start up.
        /// </summary>
        /// <param name="Doc">document</param>
        /// <param name="Wn">active window</param>
        private void Application_WindowActivate(Microsoft.Office.Interop.Word.Document Doc, Microsoft.Office.Interop.Word.Window Wn)
        {
            if (IsFirstTime)
            {
                ToParseMissingOntologies();
            }
        }

        /// <summary>
        /// This is called at opening of saved document to check for missing ontologies.
        /// </summary>
        private void ToParseMissingOntologies()
        {
            try
            {
                ConfigSettings cs = Biolit_Settings.Settings;
                if (cs.AutoStart == true)
                {
                    // Load the control collection.
                    appHandlers.LoadControlProperties(this.Application.ActiveDocument);
                    ((BioLitRibbon)Globals.Ribbons[0]).ParseOn();
                    IsFirstTime = false;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message, ExceptionTitle);
            }
        }

        /// <summary>
        /// Document before Save event handler used to serialize the custom controls present in the biolit/DB/ontology namespace.
        /// </summary>
        /// <param name="document">active document</param>
        /// <param name="saveAsUI">Save As UI</param>
        /// <param name="cancel">cancel flag</param>
        void Application_DocumentBeforeSave(Word.Document document, ref bool saveAsUI, ref bool cancel)
        {
            Word.ContentControls nodes = document.ContentControls;
            try
            {

                // check if custom markup controls are present in the document.
                if (nodes.Count > 0)
                {
                    // Retrieve all the controls properties collection.
                    ControlProperties[] savedControls = new ControlProperties[ControlsStorage.ControlCollection.Count];
                    ControlsStorage.ControlCollection.Values.CopyTo(savedControls, 0);

                    // Call the store function to serialize the custom controls.
                    ControlsStorage.Store(document, savedControls, ThisAddIn.BIOLIT_NS_URI);
                }
            }
            catch (ArgumentNullException ex)
            {
                Debug.WriteLine(ex.Message, ExceptionTitle);
            }
            catch (ArgumentOutOfRangeException ex)
            {
                Debug.WriteLine(ex.Message, ExceptionTitle);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message, ExceptionTitle);
            }
        }

        public bool IsBiolitDoc(Microsoft.Office.Interop.Word.Document doc)
        {
            return true;// do a guid based check later
        }

        internal DocumentWrapper AddDocument(Microsoft.Office.Interop.Word.Document doc)
        {
            DocumentWrapper dw = new DocumentWrapper(doc);
            AllDocs.Add(dw);
            return dw;
        }

        internal DocumentWrapper FindActiveWrapper()
        {
            foreach (DocumentWrapper dw in this.AllDocs)
            {
                if (dw.Document == this.Application.ActiveDocument)
                {
                    return dw;
                }
            }

            return AddDocument(this.Application.ActiveDocument);
        }

        internal DocumentWrapper FindWrapper(Microsoft.Office.Interop.Word.Document doc, bool AddifNotFound)
        {
            foreach (DocumentWrapper dw in this.AllDocs)
            {
                if (dw.Document == doc)
                {
                    return dw;
                }
            }
            if (AddifNotFound == true)
            {
                return AddDocument(doc);
            }

            return null;
        }

        private void RegisterSchema()
        {
            string filename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Biolit_TechPreview_Dec_2009\Biolit_schema.xsd");
            string ontologyFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Biolit_TechPreview_Dec_2009\ontology_schema.xsd");
            string dbFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Biolit_TechPreview_Dec_2009\db_schema.xsd");
            object namespaceuri = ThisAddIn.BIOLIT_NS_URI;
            object alias = "BIOLIT_MARKUP";
            try
            {
                schemaRef = this.Application.XMLNamespaces.get_Item(ref namespaceuri);
            }
            catch
            {
                schemaRef = this.Application.XMLNamespaces.Add(filename, ref namespaceuri, ref alias, false);
            }
            object namespaceonturi = ThisAddIn.ONTOLOGY_NS_URI;
            object ontologyalias = "ONTOLOGY_MARKUP";

            try
            {
                ontSchemaRef = this.Application.XMLNamespaces.get_Item(ref namespaceonturi);
            }
            catch
            {
                ontSchemaRef = this.Application.XMLNamespaces.Add(ontologyFileName, ref namespaceonturi, ref ontologyalias, false);
            }

            object namespacedburi = ThisAddIn.DB_NS_URI;
            object dbalias = "DB_MARKUP";

            try
            {
                dbSchemaRef = this.Application.XMLNamespaces.get_Item(ref namespacedburi);
            }
            catch
            {
                dbSchemaRef = this.Application.XMLNamespaces.Add(dbFileName, ref namespacedburi, ref dbalias, false);
            }
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
            foreach (DocumentWrapper dw in AllDocs)
            {
                dw.Cleanup();
            }

            this.ClearOldMenuOptions();
            ContextMenuHelper.Instance().ClearBiolitMenus();
        }

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }

        #endregion
    }
}
